`timescale 1ns/1ps
// -----------------------------------------------------------------------------
// Copyright (c) 2014-2023 All rights reserved
// *********************************************************************************
// Project Name : 
// Author       : Dark
// Create Time  : 2023-01-18 13:18:27
// Revise Time	: 2023-01-18 13:18:27
// File Name    : alu_ex.sv
// Abstract     :
`include "defines.svh"
module alu_ex(
	input	logic [ 3:0]	alu_ctrl,
	input	logic [31:0]	operand_A,
	input	logic [31:0]	operand_B,


	output  logic [31:0]	alu_out,
	output	logic			zero,	// B-type
	output	logic			less	// B-type
	);

//=================================================================================
// Signal declaration
//=================================================================================
	wire [ 4:0]	shamt; 	 // shift offset
	wire [31:0]	subdiff; // the difference of OPA OPB
//=================================================================================
// Body
//=================================================================================
	assign shamt   = operand_B[4:0];
	//assign zero    = operand_A  == operand_B;
	assign zero    = ~(|subdiff);	
	assign subdiff = operand_A  -  operand_B;
	//----------------------------------------------
	// B type Comparision
	//----------------------------------------------
	always_comb begin 
		case (alu_ctrl)
			`ALU_SLT 	: if (operand_A[31] == operand_B[31])
							less = subdiff[31];
					 	 else 
					  		less = operand_A[31];
			`ALU_SLTU 	: if (operand_A[31:0] < operand_B[31:0])
						  	less = 1'b1;
					 	  else
					  	  	less = 1'b0;
			default 	: 	less = 1'b0;
		endcase
	end
	//----------------------------------------------
	// Compution
	//----------------------------------------------
	always_comb begin 
		casez (alu_ctrl)
		   //----------------------------------------------
	       // Arithmetic
	       //----------------------------------------------
			`ALU_ADD 	: alu_out = operand_A  +  operand_B;
			`ALU_SUB 	: alu_out = subdiff;
		   //----------------------------------------------
	       // Comparision
	       //----------------------------------------------
			`ALU_SLT,`ALU_SLTU 	
						: alu_out = {31'b0,less};
		   //----------------------------------------------
	       // Shift
	       //----------------------------------------------				
			`ALU_SLL 	: alu_out = operand_A  << shamt	   ;
			`ALU_SRL 	: alu_out = operand_A  >> shamt	   ;
			`ALU_SRA 	: alu_out = ($signed(operand_A)) >>> shamt	   ;
		   //----------------------------------------------
	       // Logic
	       //----------------------------------------------
			`ALU_AND 	: alu_out = operand_A & operand_B;
			`ALU_OR  	: alu_out = operand_A | operand_B;
			`ALU_XOR 	: alu_out = operand_A ^ operand_B;
			`ALU_B   	: alu_out = operand_B;
			default  	: alu_out = `ZEROWORD;
		endcase	
	end


endmodule
